package com.rtsapp.server.utils.logger;

import java.util.*;

/**
 *  一个周期性时间的帮助类
 *  设定一个周期类型和周期偏移, 给定当前时间, 计算下一个周期的开始时间
 */
public class RollingCalendar extends GregorianCalendar {

    private static final long serialVersionUID = -3560331770601814177L;


    /**
     * 一个错误类型
     */
    static final int TOP_OF_TROUBLE = -1;
    /**
     * 以分为周期
     */
    public static final int TOP_OF_MINUTE = 0;
    /**
     * 以小时为周期
     */
    public static final int TOP_OF_HOUR = 1;
    /**
     * 以半天为周期
     */
    public static final int HALF_DAY = 2;

    /**
     * 以天为周期
     */
    public static final int TOP_OF_DAY = 3;

    /**
     * 以星期为周期
     */
    public static final int TOP_OF_WEEK = 4;

    /**
     * 以月为周期
     */
    public static final int TOP_OF_MONTH = 5;


    //周期类型
    private int type = RollingCalendar.TOP_OF_TROUBLE;
    //周期的偏移
    private int offset = 0;

    public RollingCalendar( ) {
        super();
    }

    public RollingCalendar( TimeZone tz, Locale locale ) {
        super(tz, locale);
    }

    /**
     * 设置日历的类型
     * @param type 周期类型
     * @param offset offset为该类型下的时间偏移(单位为该类型的子单位), 如果周期为分,偏移单位是秒, 如果周期是天,偏移是小时
     */
    public void setType(int type, int offset ) {
        this.type = type;
        if( offset < 0 ){
            throw new RuntimeException( "offset 不能小于0" );
        }
        switch (type) {
            case RollingCalendar.TOP_OF_MINUTE:
                if( offset >= 60 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            case RollingCalendar.TOP_OF_HOUR:
                if( offset >= 60 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            case RollingCalendar.HALF_DAY:
                if( offset >= 12 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            case RollingCalendar.TOP_OF_DAY:
                if( offset >= 24 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            case RollingCalendar.TOP_OF_WEEK:
                if( offset >= 7 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            case RollingCalendar.TOP_OF_MONTH:
                if( offset >= 28 ){
                    throw new RuntimeException( "offset错误" );
                }
                break;
            default:
                throw new IllegalStateException("Unknown periodicity type.");
        }
        this.offset = offset;
    }

    /**
     * 获得下一个周期的开始时间
     * @param now
     * @return 返回值是毫秒
     */
    public long getNextCheckMillis(Date now) {
        return getNextCheckDate(now).getTime();
    }


    /**
     * 获得下一个周期的开始时间
     * @param nowMillis
     * @return 返回值是毫秒
     */
    public long getNextCheckMillis( long nowMillis ) {
        return getNextCheckDate( nowMillis ).getTime();
    }

    /**
     * 获得下一个周期的开始时间
     * @param now 当前时间
     * @return 下一个时间
     */
    public Date getNextCheckDate(Date now) {
        this.setTime(now);
        return getNextCheckDate();
    }

    /**
     * 获得下一个周期的开始时间
     * @param nowMillis 当前的毫秒时间
     * @return 下一个周期开始时间Date
     */
    public Date getNextCheckDate( long nowMillis ) {
        this.setTimeInMillis(nowMillis );
        return getNextCheckDate();
    }


    private Date getNextCheckDate(){
        switch (type) {
            case RollingCalendar.TOP_OF_MINUTE:
                this.set(Calendar.SECOND, this.offset );
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.MINUTE, 1);
                break;
            case RollingCalendar.TOP_OF_HOUR:
                this.set(Calendar.MINUTE, this.offset );
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.HOUR_OF_DAY, 1);
                break;
            case RollingCalendar.HALF_DAY:
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                int hour = get(Calendar.HOUR_OF_DAY);
                if (hour < 12 + this.offset ) {
                    this.set(Calendar.HOUR_OF_DAY, 12 + this.offset );
                } else {
                    this.set(Calendar.HOUR_OF_DAY, this.offset );
                    this.add(Calendar.DAY_OF_MONTH, 1);
                }
                break;
            case RollingCalendar.TOP_OF_DAY:
                this.set(Calendar.HOUR_OF_DAY, this.offset );
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.DATE, 1);
                break;
            case RollingCalendar.TOP_OF_WEEK:
                this.set(Calendar.DAY_OF_WEEK, getFirstDayOfWeek() + this.offset );
                this.set(Calendar.HOUR_OF_DAY, 0);
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.WEEK_OF_YEAR, 1);
                break;
            case RollingCalendar.TOP_OF_MONTH:
                this.set(Calendar.DATE, 1 + this.offset );
                this.set(Calendar.HOUR_OF_DAY, 0);
                this.set(Calendar.MINUTE, 0);
                this.set(Calendar.SECOND, 0);
                this.set(Calendar.MILLISECOND, 0);
                this.add(Calendar.MONTH, 1);
                break;
            default:
                throw new IllegalStateException("Unknown periodicity type.");
        }
        return getTime();
    }
}

